/**
 ******************************************************************************
 * @file    
 * @author 
 * @Version 
 * @Date    
 * @brief 
 *******************************************************************************  
 **/
#include "zb32l03x_hal.h"
#include "bsp_powerctrl.h"
#include "bsp_loop.h"
#include "app_loop.h"
#include "FreeRTOS.h"
#include "log.h"
#include "task.h"
#include "queue.h"
#include "event_groups.h"
#include "user_eventflag.h"
extern PRIVILEGED_DATA TaskHandle_t looptask_handler;
extern loopctrlinfo_t loopctrlinfo;
/**
  * @brief  总线初始化
  * @param  
  * @param  
  * @retval 
  */
 void app_loop_init(void)
 {
   loopctrlinfo.mode=LOOPMODE_9000;
   bsp_loop_init();
 }

 /**
  * @brief  设置总线模式
  * @param  
  * @param  
  * @retval 
  */
void app_loop_setmode(loopmode_e mode)
{
   loopctrlinfo.mode=mode; 
}

/**
  * @brief  发送信息转换成脉冲宽度
  * @param  
  * @param  
  * @retval 
  */

 void app_loop_sendinfotobit(businfo_t *info, loopctrlinfo_t *ctrl)
 {
    uint8_t i=0,j;
    uint32_t totaltime = 0; //有用区域宽度
    ctrl->loopsendcodectrl.item=0;
    info->cmdcheck=0;
    info->addcheck=0;
    if (ctrl->mode == LOOPMODE_9000)
    {
      //起始码
      ctrl->loopsendcodectrl.halfbittime[i++]=LOOPMODE_9000_LOW_START; 
      ctrl->loopsendcodectrl.halfbittime[i++]=LOOPMODE_9000_HIGHT_START;
     
      //命令码,高位先发
      for (j = 0; j < 7; j++)
      {
          if ((info->cmd >> (6 - j)) & 0x01)
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
              info->cmdcheck++;
          }
          else
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_0;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_0;
          }
      }
      //地址码,高位先发
      for (j = 0; j < 9; j++)
      {
          if ((info->address >> (8 - j)) & 0x01)
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
              info->addcheck++;
          }
          else
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_0;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_0;
          }
      }
      //命令校验码
      if (info->cmdcheck & 0x01)
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
      }
      else
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_0;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_0;
      }
      //地址校验码
      if (info->addcheck & 0x01)
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
      }
      else
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_0;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_0;
      }
      //空格码
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_SPACE;
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_SPACE;
      // 回码区
      for (j = 0; j < 16; j++)
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
          info->backcodecheck++;
      }
      //在线位
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
      //校验
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_HIGHT_1;
      //空闲区
      for (j = 0; j < i; j++)
      {
          totaltime = totaltime + ctrl->loopsendcodectrl.halfbittime[j];
      }
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_9000_LOW_1;
      ctrl->loopsendcodectrl.halfbittime[i++] = 100000-totaltime;
    }
    else
    {
      //起始码
      ctrl->loopsendcodectrl.halfbittime[i++]=LOOPMODE_EPC_LOW_START; 
      ctrl->loopsendcodectrl.halfbittime[i++]=LOOPMODE_EPC_HIGHT_START;
      //命令码,高位先发
      for (j = 0; j < 7; j++)
      {
          if ((info->cmd >> (6 - j)) & 0x01)
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
              info->cmdcheck++;
          }
          else
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_0;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_0;
          }
      }
      //地址码,高位先发
      for (j = 0; j < 9; j++)
      {
          if ((info->address >> (8 - j)) & 0x01)
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
              info->addcheck++;
          }
          else
          {
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_0;
              ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_0;
          }
      }
      //命令校验码
      if (info->cmdcheck & 0x01)
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
      }
      else
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_0;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_0;
      }
      //地址校验码
      if (info->addcheck & 0x01)
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
      }
      else
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_0;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_0;
      }
      //空格码
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_SPACE;
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_SPACE;
      // 回码区
      for (j = 0; j < 16; j++)
      {
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
          ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
          info->backcodecheck++;
      }
      //在线位
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
      //校验
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_HIGHT_1;
      //空闲区
      for (j = 0; j < i; j++)
      {
          totaltime = totaltime + ctrl->loopsendcodectrl.halfbittime[j];
      }
      ctrl->loopsendcodectrl.halfbittime[i++] = LOOPMODE_EPC_LOW_1;
      ctrl->loopsendcodectrl.halfbittime[i++] = 100000-totaltime;
    }
    
 }
/**
  * @brief  打开回路
  * @param  
  * @param  
  * @retval 
  */
 uint8_t app_loop_open(void)
 {
    if (app_powerctrl_isshortdet() == 0)
    {

      BSP_POWERCTRL_POWERON();
      app_loop_sendbit_level(1);
      vTaskDelay(1000);
      return 1;
    }
    else
    {
      BSP_POWERCTRL_POWEROFF();
      app_loop_sendbit_level(0);
      return 0;
    }
 }

/**
  * @brief  关闭回路
  * @param  
  * @param  
  * @retval 
  */
 void app_loop_close(void)
 {
    BSP_POWERCTRL_POWEROFF();
    app_loop_sendbit_level(0);
    BSP_LOOP_SENDCODE_TIM_DISABLE();
 }
/**
  * @brief  设置回路电平
  * @param  
  * @param  
  * @retval 
  */
 void  app_loop_sendbit_level(uint8_t level)
 {
    BSP_LOOP_SEND_OUT(level&0x01);
    
 }
/**
  * @brief  回路开始触发
  * @param  
  * @param  
  * @retval 
  */

 void app_loop_sendcodestart(loopctrlinfo_t *ctrl)
 {
   //开始触发
   app_loop_setdate(1,ctrl->loopsendcodectrl.halfbittime[0]);
   app_loop_setdate(0,ctrl->loopsendcodectrl.halfbittime[1]);
   app_loop_sendbit_level(ctrl->loopsendcodectrl.item & 0x01);
   ctrl->loopsendcodectrl.item++;
   BSP_LOOP_SENDCODE_TIM->INTCLR |= (BASETIM_INTCLR_INTCLR);
   BSP_LOOP_SENDCODE_TIM_ENABLE();
      
 }

void app_loop_sendcodestop(void)
{
   //停止触发
   BSP_LOOP_SENDCODE_TIM->INTCLR &= ~(BASETIM_INTCLR_INTCLR);
   BSP_LOOP_SENDCODE_TIM_DISABLE();
      
 }

/*
*********************************************************************************************************
*	功能说明: 设置脉宽
*	形    参: 
*	返 回 值: 
* 说    明：
*********************************************************************************************************
*/

void app_loop_setdate(uint8_t flag, uint32_t time)
{
    uint32_t period;
    period = BASETIM_MAXCNTVALUE_32BIT - time;
    if (flag)
    {
        BSP_LOOP_SENDCODE_TIM->LOAD = period;
    }
    else
    {
        BSP_LOOP_SENDCODE_TIM->BGLOAD = period;
    }
}

/*
*********************************************************************************************************
*	功能说明: 初始化回码缓冲区
*	形    参: 
*	返 回 值: 
*   说    明：
*********************************************************************************************************
*/

void app_loop_decodebuffsampleinit(loopctrlinfo_t *ctrl)
{
    for (uint8_t i = 0; i < sizeof(ctrl->loopdecodectrl.backcodeadcvalbuffitem); i++)
    {
        ctrl->loopdecodectrl.backcodeadcvalbuffitem[i] = 0;
    }
    ctrl->loopdecodectrl.baseadcval = 0;
    ctrl->loopdecodectrl.senditem = 0;
    if (ctrl->mode == LOOPMODE_9000)
    {
        ctrl->loopdecodectrl.samplenum = APP_LOOP_BACKCODE_SAMPLE_NUM;          // 采样数量
        ctrl->loopdecodectrl.samplegap = APP_LOOP_BACKCODE_SAMPLE_GAP;          // 采样间隔
        ctrl->loopdecodectrl.sampledelay = APP_LOOP_BACKCODE_SAMPLE_DELAY_9000; // 采样延时
    }
    else
    {
        ctrl->loopdecodectrl.samplenum = APP_LOOP_BACKCODE_SAMPLE_NUM;         // 采样数量
        ctrl->loopdecodectrl.samplegap = APP_LOOP_BACKCODE_SAMPLE_GAP;         // 采样间隔
        ctrl->loopdecodectrl.sampledelay = APP_LOOP_BACKCODE_SAMPLE_DELAY_EPC; // 采样延时
    }
     bsp_loop_backcodesampleinit();
}

/*
*********************************************************************************************************
*	功能说明: 开始采样回码
*	形    参: 
*	返 回 值: 
* 说    明：
*********************************************************************************************************
*/
void app_loop_backcodesamplestart(loopctrlinfo_t *ctrl)
{
    bsp_loop_backcodesamplestart();
    BSP_LOOP_BACKCODE_DELAYSAMPLE_TIM_DISABLE();
    BSP_LOOP_BACKCODE_DELAYSAMPLE_TIM->LOAD = BASETIM_MAXCNTVALUE_32BIT-ctrl->loopdecodectrl.sampledelay; 
   
    BSP_LOOP_BACKCODE_DELAYSAMPLE_ENABLE();
}

/**
  * @brief  发码处理
  * @param  
  * @param  
  * @retval 
  */

void app_loop_sendcode(loopctrlinfo_t *ctrl)
{
    /* TIM Update event */
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if (ctrl->loopsendcodectrl.item < (sizeof(ctrl->loopsendcodectrl.halfbittime) / sizeof(ctrl->loopsendcodectrl.halfbittime[0])))
    {
        app_loop_sendbit_level(ctrl->loopsendcodectrl.item);
        // 开始采样
        if ((ctrl->loopsendcodectrl.item >= 38) && ((ctrl->loopsendcodectrl.item & 0x01) == 0))
        {
          app_loop_backcodesamplestart(ctrl);
        }
        // 更新下一个总线bit
        ctrl->loopsendcodectrl.item++;
        app_loop_setdate(0, ctrl->loopsendcodectrl.halfbittime[ctrl->loopsendcodectrl.item]);
    }
    else
    {   
        app_loop_sendcodestop();
        xTaskNotifyFromISR(looptask_handler, NOTIFY_LOOPTASK_SENDDATEBIT, eSetBits, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

/**
  * @brief  回码解析处理
  * @param  
  * @param  
  * @retval 
  */

void app_loop_getbackcode(loopctrlinfo_t *ctrl)
{

    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    ctrl->loopdecodectrl.backcodeadcvalbuff[ctrl->loopdecodectrl.senditem][ctrl->loopdecodectrl.backcodeadcvalbuffitem[ctrl->loopdecodectrl.senditem]] = READ_REG(ADC->RESULT);
    ctrl->loopdecodectrl.backcodeadcvalbuffitem[ctrl->loopdecodectrl.senditem]++;
    if (ctrl->loopdecodectrl.backcodeadcvalbuffitem[ctrl->loopdecodectrl.senditem] >= ctrl->loopdecodectrl.samplenum)
    {
        bsp_loop_backcodesamplestop();
        ctrl->loopdecodectrl.senditem++;
        // 发送解码通知
        if (ctrl->loopdecodectrl.senditem >= (sizeof(ctrl->loopdecodectrl.backcodeadcvalbuff) / sizeof(ctrl->loopdecodectrl.backcodeadcvalbuff[0])))
        {
          xTaskNotifyFromISR(looptask_handler, NOTIFY_LOOPTASK_DECODE, eSetBits, &xHigherPriorityTaskWoken);
        }
        xTaskNotifyFromISR(looptask_handler, NOTIFY_LOOPTASK_BCAKCODESAMPLE_FINISH, eSetBits, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

/*
*********************************************************************************************************
*	功能说明: 解码
*	形    参: 
*	返 回 值: 
*   说    明：
*********************************************************************************************************
*/
uint32_t app_loop_decode(loopctrlinfo_t *ctrl)
{
    uint8_t i, j;
    uint32_t sum;
    uint32_t result = 0;
    uint16_t decodebase = 0;

    for (i = 0; i < ctrl->loopdecodectrl.senditem; i++)
    {
        sum = 0;
        for (j = 0; j < ctrl->loopdecodectrl.backcodeadcvalbuffitem[i]; j++)
        {
          sum = sum + ctrl->loopdecodectrl.backcodeadcvalbuff[i][j];
        }
        sum = sum / j;
        // 计算基准电压
        if (i == 0)
        {
          decodebase = sum;
        }
        else 
        {
          result <<= 1;
          // 大于10mA，小于40mA就认为有回码，对于为20mV和80mV 20mV=(20/2500)*4095=32,80mv=(80/2500)*4095=131
          if ((sum > decodebase) && ((sum - decodebase > 32) && (sum - decodebase < 131)))
          {
              result++;
          }
          
        }
    }
#if 0
    msg("senditem=%d\r\n", ctrl->loopdecodectrl.senditem);
    for (i = 0; i < ctrl->loopdecodectrl.senditem; i++)
    {
       for (j = 0; j < ctrl->loopdecodectrl.backcodeadcvalbuffitem[i]; j++)
       {
         msg("backcodeadcval[%d][%d]=%d\r\n", i,j,ctrl->loopdecodectrl.backcodeadcvalbuff[i][j]);
         vTaskDelay(5);
       }
       msg("****\r\n");
    }
#endif
    return result;
}

/*
*********************************************************************************************************
*	函 数 名: app_loop_bcakcodecheck
*	功能说明: 计算校验位
*	形    参: val:需要计算的值  bitlen：val长度，单位：bit
*	返 回 值: 校验结果
*********************************************************************************************************
*/
uint8_t app_loop_bcakcodecheck(businfo_t*info)
{
  uint8_t i, cmdcheck = 0;
  uint32_t res=(info->backcodedate<<1)|(info->online);
  for (i = 0; i < 17; i++)
  {
    cmdcheck ^= ((res >> (16 - i))&0x01);
  }
  return cmdcheck;
}

/******************************************************************************
* 函 数 名: LoopPointTest
* 功能说明: 对终端进行单点测试
* 形    参: mode：通信方式  adrr:地址 
* 返 回 值: 0:不在线  1：在线  2:重码
******************************************************************************/
uint8_t app_loop_pointtest(uint8_t mode, int adrr)
{
  app_loop_setmode(mode);

  loopctrlinfo.sendinfo.cmd = LOOPID_POINT_TEST; //单点测试
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }
  return 1;
}


/******************************************************************************
* 函 数 名: LoopWriteCode
* 功能说明: 写地址操作
* 形    参: sendinfo:回码信息  mode：通信方式 adrr:需要写入的地址
* 返 回 值: 0:写入失败  1：写入成功,为单地址 2：写入成功,为双地址
******************************************************************************/
int app_loop_writecode(loopmode_e mode, int adrr)
{
  int resadrr_1 = 0;
  int resadrr_2 = 0;
  int resadrr = 0;

 
  app_loop_setmode(mode);

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS; //1.先读码
  loopctrlinfo.sendinfo.address = 0xAA;
  app_loop_sendinfotobus();
  
  


  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ADREESS; //2.第一次发送写码命令，需要发送两次
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  
 

  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ADREESS; //3.第二次发送写码命令，需要发送两次
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  
  

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS; //4.读回地址确认是否编码成功
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
   
  
  resadrr_1 = loopctrlinfo.sendinfo.backcodedate & 0X01FF;

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS; //5.读回地址确认是否编码成功,A58使用
  loopctrlinfo.sendinfo.address = 0x99;
  app_loop_sendinfotobus();
   
  
  resadrr_2 = loopctrlinfo.sendinfo.backcodedate & 0X01FF;

  if ((resadrr_1 == adrr) && (resadrr_1 + 1 == resadrr_2))
  {
    resadrr = 2;
  }
  else if(resadrr_1 == adrr)
  {
    resadrr = 1;
  }
  else
  {
    resadrr = 0;
  }

  return resadrr;
}

/******************************************************************************
* 函 数 名: app_loop_readcode
* 功能说明: 读地址操作
* 形    参: mode：通信方式  adrr:读回的地址
* 返 回 值: 0:读入失败  1：读回单地址 2：读回双地址
******************************************************************************/
int app_loop_readcode(uint8_t mode,int *adrr)
{
  int resadrr_1 = 0;
  int resadrr_2 = 0;
  int resadrr = 0;

  app_loop_setmode(mode);


  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  resadrr_1 = loopctrlinfo.sendinfo.backcodedate & 0X01FF;

  loopctrlinfo.sendinfo.cmd = 0x2F;//A58使用
  loopctrlinfo.sendinfo.address = 0x99;
  app_loop_sendinfotobus();
  resadrr_2 = loopctrlinfo.sendinfo.backcodedate & 0X01FF;

  if((resadrr_1>324)||(resadrr_1==0))
  {
    resadrr = 0;
  }
  else if ((resadrr_1 + 1) == resadrr_2)//双地址
  {
    resadrr = 2;
    if (adrr > NULL)
    {
          *adrr = resadrr_1;
    }
  }
  else//单地址
  {
    resadrr = 1;
    if (adrr > NULL)
    {
          *adrr = resadrr_1;
    }
  }
  return resadrr;
}
/******************************************************************************
* 函 数 名: app_loop_modelmodeset
* 功能说明: 设置模块模式
* 形    参: mode：通信方式  modesel:模块的模式 
* 返 回 值: 0:设置失败  1：设置成功
******************************************************************************/
uint8_t app_loop_modelmodeset(uint8_t mode,int modesel)
{
  uint16_t adrr = 0,id = 0;
  uint8_t factorytype=0;

  app_loop_setmode(mode);


  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;
  
  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;
  if ((adrr <= 0) || (adrr > 324)) //地址不合法
  {
    return 0;
  }
  

  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ALARMVALUE;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();


  
  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ALARMVALUE_BYBE;
  loopctrlinfo.sendinfo.address = ((modesel >> 8) & 0x0003); //写报警值高2位命令;
  app_loop_sendinfotobus();
  id = loopctrlinfo.sendinfo.backcodedate >> 8;
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || ((id ^ (loopctrlinfo.sendinfo.backcodedate & 0xff)) != 0xff))
  {
    return 0;
  }

  
  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ALARMVALUE_BYBE;
  loopctrlinfo.sendinfo.address = modesel & 0xff; //写模式低8位命令;
  app_loop_sendinfotobus();
  id = loopctrlinfo.sendinfo.backcodedate >> 8;
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || ((id ^ (loopctrlinfo.sendinfo.backcodedate & 0xff)) != 0xff))
  {
    return 0;
  }

  vTaskDelay(50);//延时50ms，让终端闪灯后再读
  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ALARMVALUE;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || (loopctrlinfo.sendinfo.backcodedate != modesel))
  {
    return 0;
  }
  return 1;
}
/******************************************************************************
* 函 数 名: app_loop_modelmodeget
* 功能说明: 获取模块模式
* 形    参: mode：通信方式  modesel:模块的模式 
* 返 回 值: 0:获取失败  1：获取成功
******************************************************************************/
uint8_t app_loop_modelmodeget(uint8_t mode, int *modesel)
{
  uint16_t adrr = 0;
  uint8_t factorytype=0;

  app_loop_setmode(mode);
  
  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;

  if ((adrr == 0) || (adrr > 324))
  {
    return 0;
  }

  
  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ALARMVALUE;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }
  *modesel = (loopctrlinfo.sendinfo.backcodedate& 0xff);
  return 1;
}
/******************************************************************************
* 函 数 名: SounderModeSet
* 功能说明: 设置声光模式
* 形    参: mode：通信方式  modesel:声光的模式 
* 返 回 值: 0:设置失败  1：设置成功
******************************************************************************/
uint8_t app_loop_soundermodeset(uint8_t mode,int modesel)
{
  uint16_t adrr = 0,id = 0;
  uint8_t factorytype=0;

  app_loop_setmode(mode);
 

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;
  if ((adrr <= 0) || (adrr > 324)) //地址不合法
  {
    return 0;
  }


  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_WORKMODE; //写工作模式
  loopctrlinfo.sendinfo.address = adrr;
   app_loop_sendinfotobus();

  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_WORKMODE; //写工作模式
  loopctrlinfo.sendinfo.address = modesel + 324;
  app_loop_sendinfotobus();

  
  loopctrlinfo.sendinfo.cmd = LOOPID_READ_WORKMODE; //读工作模式
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  id = loopctrlinfo.sendinfo.backcodedate >> 8;

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || (id != modesel))
  {
    return 0;
  }
  return 1;
}
/******************************************************************************
* 函 数 名: app_loop_soundermodeget
* 功能说明: 或缺模块模式
* 形    参: mode：通信方式  modesel:模块的模式 
* 返 回 值: 0:获取失败  1：获取成功
******************************************************************************/
uint8_t app_loop_soundermodeget(uint8_t mode, int *modesel)
{
  uint16_t adrr = 0;
  uint8_t factorytype=0;

  app_loop_setmode(mode);

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;

  if ((adrr == 0) || (adrr > 324))
  {
    return 0;
  }


  loopctrlinfo.sendinfo.cmd = LOOPID_READ_WORKMODE; //读工作模式
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
 

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }
  *modesel = (loopctrlinfo.sendinfo.backcodedate >> 8);
  return 1;
}

/******************************************************************************
* 函 数 名: LoopOperateLamp
* 功能说明: 对标志灯操作
* 形    参: mode：0：常亮  1：闪亮  adrr:地址  onoff:1打开 0停止
* 返 回 值: 0:失败  1：成功
******************************************************************************/
uint8_t app_loop_operatelamp(int adrr,uint8_t onoff,uint8_t mode)
{
 
  uint8_t unitnum;//地址所处的组
  uint8_t res = 0;
  unitnum = adrr % 18;
  if (unitnum == 0)
  {
    unitnum = 18;
  }
  if (mode == 0)
  {
    for (res = 0; res < 3; res++)
    {
      loopctrlinfo.sendinfo.cmd = LOOPID_FAULT_CHECK;
      loopctrlinfo.sendinfo.address = unitnum;
      app_loop_sendinfotobus();
    }

    for (res = 0; res < 10; res++)
    {
      if (onoff == 0)
      {
        loopctrlinfo.sendinfo.cmd = LOOPID_OFF_LAMP;
      }
      else
      {
        loopctrlinfo.sendinfo.cmd = LOOPID_ON_LAMP;
      }
      loopctrlinfo.sendinfo.address = adrr ;
      app_loop_sendinfotobus();
      if ((loopctrlinfo.sendinfo.backcodecheck == app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) && (loopctrlinfo.sendinfo.online == 1))
      {
        break;
      }
    }
  }
  else
  {
    for (res = 0; res < 2; res++)
    {
      loopctrlinfo.sendinfo.cmd = LOOPID_FAULT_CHECK;
      loopctrlinfo.sendinfo.address = unitnum;
      app_loop_sendinfotobus();
    }

    for (res = 0; res < 2; res++)
    {
      if (onoff == 0)
      {
        loopctrlinfo.sendinfo.cmd = LOOPID_OFF_LAMP;
      }
      else
      {
        loopctrlinfo.sendinfo.cmd = LOOPID_ON_LAMP;
      }
      loopctrlinfo.sendinfo.address = adrr|0x100 ;
      app_loop_sendinfotobus();
    }

    for (res = 0; res < 2; res++)
    {
     
      loopctrlinfo.sendinfo.cmd = LOOPID_NORMAL_CHECK;
      loopctrlinfo.sendinfo.address = adrr ;
      app_loop_sendinfotobus();
    }
  }

  return res;
}

/******************************************************************************
* 函 数 名: ElectricalDHSet
* 功能说明: 电气火灾参数设置
* 形    参: mode：通信方式  modesel:模块的模式 
* 返 回 值: 0:设置失败  1：设置成功
******************************************************************************/
uint8_t app_loop_electricaldhset(uint8_t mode,uint16_t modesel)
{
  
  
  
  uint16_t adrr = 0,id = 0;
  uint8_t factorytype=0;

  app_loop_setmode(mode);


  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;
  if ((adrr <= 0) || (adrr > 324)) //地址不合法
  {
    return 0;
  }

  loopctrlinfo.sendinfo.cmd = LOOPID_NORMAL_CHECK;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || (loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }

  factorytype = ((loopctrlinfo.sendinfo.backcodedate >> 10) & 0x003f); //高6位为生产类型

  if ((factorytype != MKID_ELECTRICALDH_TEMPERATURE) && (factorytype != MKID_ELECTRICALDH_CURRENT)) //不是剩余电流式探测器或者测温式电气火灾探测器
  {
    return 0;
  }

  if (factorytype == MKID_ELECTRICALDH_CURRENT)//剩余电流报警设定值不合法
  {
     if((modesel<30)||(modesel>1000)) 
     {
       return 0;
     }
  }

  if (factorytype == MKID_ELECTRICALDH_TEMPERATURE)//温度报警设定值不合法
  {
     if((modesel<45)||(modesel>140)) 
     {
       return 0;
     }
  }


  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ALARMVALUE;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();

  factorytype = ((loopctrlinfo.sendinfo.backcodedate  >> 10) & 0x003f); //高6位为生产类型
  id = loopctrlinfo.sendinfo.backcodedate  & 0X01FF;

  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ALARMVALUE_BYBE;
  loopctrlinfo.sendinfo.address = ((modesel >> 8) & 0x0003); //写报警值高2位命令;
  app_loop_sendinfotobus();

  id = loopctrlinfo.sendinfo.backcodedate >> 8;
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || ((id ^ (loopctrlinfo.sendinfo.backcodedate & 0xff)) != 0xff))
  {
    return 0;
  }

  loopctrlinfo.sendinfo.cmd = LOOPID_WRITE_ALARMVALUE_BYBE;
  loopctrlinfo.sendinfo.address = modesel & 0xff; //写模式低8位命令;
  app_loop_sendinfotobus();

  id = loopctrlinfo.sendinfo.backcodedate >> 8;
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || ((id ^ (loopctrlinfo.sendinfo.backcodedate & 0xff)) != 0xff))
  {
    return 0;
  }

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ALARMVALUE;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  if(factorytype == MKID_ELECTRICALDH_TEMPERATURE)
  {
    loopctrlinfo.sendinfo.backcodedate = (loopctrlinfo.sendinfo.backcodedate& 0xff);//若为测温式探测器，则回码后8位为温度报警设定值
  }
  
  if(factorytype == MKID_ELECTRICALDH_CURRENT)
  {
    loopctrlinfo.sendinfo.backcodedate= (loopctrlinfo.sendinfo.backcodedate & 0x03ff); //若为剩余电流式探测器，则回码后10位为剩余电流报警设定值
  }
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || (loopctrlinfo.sendinfo.backcodedate != modesel))
  {
    return 0;
  }
  return 1;
}
/******************************************************************************
* 函 数 名: ElectricalDHGet
* 功能说明: 电气火灾参数
* 形    参: mode：通信方式  modesel:电气火灾参数 
* 返 回 值: 0:获取失败  1：获取成功
******************************************************************************/
uint8_t app_loop_electricaldhget(uint8_t mode, int *modesel)
{

  uint16_t adrr = 0;
  uint8_t factorytype=0;

  app_loop_setmode(mode);

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate  & 0X01FF;

  if ((adrr == 0) || (adrr > 324))
  {
    return 0;
  }

  loopctrlinfo.sendinfo.cmd = LOOPID_NORMAL_CHECK;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {

    return 0;
  }

  factorytype = ((loopctrlinfo.sendinfo.backcodedate >> 10) & 0x003f); //高6位为生产类型

   if ((factorytype != MKID_ELECTRICALDH_TEMPERATURE) && (factorytype != MKID_ELECTRICALDH_CURRENT)) //不是剩余电流式探测器或者测温式电气火灾探测器
  {
    return 0;
  }

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ALARMVALUE;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }
  if(factorytype == MKID_ELECTRICALDH_TEMPERATURE)
  {
    *modesel = (loopctrlinfo.sendinfo.backcodedate& 0xff);//若为测温式探测器，则回码后8位为温度报警设定值
  }
  
  if(factorytype == MKID_ELECTRICALDH_CURRENT)
  {
     *modesel= (loopctrlinfo.sendinfo.backcodedate & 0x03ff); //若为剩余电流式探测器，则回码后10位为剩余电流报警设定值
  }
  return 1;
}


/******************************************************************************
* 函 数 名: app_loop_isblacklist
* 功能说明: 判断命令是不是黑名单的
* 形    参: 
* 返 回 值: 
******************************************************************************/
static const uint16_t blacklist[][10] = {
    {0x0204, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0b, 0x0c},
    {0x0205, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0b, 0x0c},
    {0x0502, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0b, 0x0c},
    {0x0503, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0b, 0x0c},
} ;

bool app_loop_isblacklist(uint16_t type, uint8_t fun)
{
  int i, j;
  bool res = false;
  if (fun == 0x7f)
  {
     return true;
  }
  for (i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++)
  {
     if (type == blacklist[i][0])
     {
       for (j = 1; j < sizeof(blacklist[0]) / sizeof(blacklist[0][0]); j++)
       {
        if (fun == blacklist[i][j])
        {
          res = true;
          break;
        }
       }
       if (res == true)
       {
        break;
       }
     }
  }
  return res;
}

/******************************************************************************
* 函 数 名: app_loop_mulfunset
* 功能说明: 多功能编码器设置
* 形    参: mode：通信方式
* 返 回 值: 0:设置失败  1：设置成功
******************************************************************************/
uint8_t app_loop_mulfunset(uint8_t mode, uint8_t subfun, uint16_t para,uint8_t blacklisten)
{

  uint16_t adrr = 0;

  uint8_t typemain ;
  uint8_t typesub ;

  app_loop_setmode(mode);

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate & 0X01FF;
  if ((adrr <= 0) || (adrr > 324)) // 地址不合法
  {
     return 0;
  }

  // 写入
  loopctrlinfo.sendinfo.cmd = 0x27;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();

  typemain = loopctrlinfo.sendinfo.backcodedate>>10;
  typesub  = loopctrlinfo.sendinfo.backcodedate&0xff;
  msg("typemain=0x%x,typesub=0x%x\r\n",typemain,typesub);

  if ((blacklisten == 1) && (app_loop_isblacklist(typemain << 8 | typesub, subfun) == true))
  {
     msg("blacklist\r\n");
     return 0;
  }

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || (loopctrlinfo.sendinfo.online != 1))
  {
     return 0;
  }

  loopctrlinfo.sendinfo.cmd = 0x5E;
  loopctrlinfo.sendinfo.address = subfun+128;
  app_loop_sendinfotobus();

  loopctrlinfo.sendinfo.cmd = 0x5C;
  loopctrlinfo.sendinfo.address = (para)&0xff;
  app_loop_sendinfotobus();

  loopctrlinfo.sendinfo.cmd = 0x5C;
  loopctrlinfo.sendinfo.address = (para >> 8) & 0xff;
  app_loop_sendinfotobus();

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo)) || (loopctrlinfo.sendinfo.online != 1))
  {
     return 0;
  }
  adrr = 0;
  if (app_loop_mulfunget(mode, subfun, &adrr) && (adrr == para))
  {

     return 1;
  }
  else
  {
     return 0;
  }
}
/******************************************************************************
* 函 数 名: ElectricalDHGet
* 功能说明: 电气火灾参数
* 形    参: mode：通信方式  modesel:电气火灾参数 
* 返 回 值: 0:获取失败  1：获取成功
******************************************************************************/
uint8_t app_loop_mulfunget(uint8_t mode, uint8_t subfun,uint16_t *modesel)
{

  uint16_t adrr = 0;

  app_loop_setmode(mode);

  loopctrlinfo.sendinfo.cmd = LOOPID_READ_ADREESS;
  loopctrlinfo.sendinfo.address = 0x55;
  app_loop_sendinfotobus();
  adrr = loopctrlinfo.sendinfo.backcodedate  & 0X01FF;

  if ((adrr == 0) || (adrr > 324))
  {
    return 0;
  }

  loopctrlinfo.sendinfo.cmd = 0x27;
  loopctrlinfo.sendinfo.address = adrr;
  app_loop_sendinfotobus();
  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {

    return 0;
  }


  loopctrlinfo.sendinfo.cmd = 0x2e;
  loopctrlinfo.sendinfo.address = subfun;
  app_loop_sendinfotobus();

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }

  adrr=(loopctrlinfo.sendinfo.backcodedate>>8);
  


  loopctrlinfo.sendinfo.cmd = 0x2e;
  loopctrlinfo.sendinfo.address = subfun+128;
  app_loop_sendinfotobus();

  if ((loopctrlinfo.sendinfo.backcodecheck != app_loop_bcakcodecheck(&loopctrlinfo.sendinfo))||(loopctrlinfo.sendinfo.online != 1))
  {
    return 0;
  }
  adrr=adrr|((loopctrlinfo.sendinfo.backcodedate>>8)<<8);
  *modesel = adrr;
  return 1;
}

/******************************************************************************
* 函 数 名: app_loop_waitbackcode
* 功能说明: 等待回码
* 形    参: 
* 返 回 值: 
******************************************************************************/
void app_loop_sendinfotobus(void)
{
  BaseType_t res;
  uint16_t revinfo;
  xEventGroupSetBits(xEventGroup,EVENTGROUP_LOOPSEND_START);
  xEventGroupWaitBits(xEventGroup,EVENTGROUP_LOOPSEND_END,pdTRUE,pdTRUE,portMAX_DELAY);
 
}
